#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#ifdef _WIN32
#include <WinSock2.h>
#include <Windows.h>
#else
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif//_WIN32

#ifndef _WIN32
typedef int SOCKET;
#define INVALID_SOCKET      (-1)
#define SOCKET_ERROR        (-1)
#define CLOSE_SOCK(sk)      close((sk))
#define LAST_ERROR()        errno
#else
#define CLOSE_SOCK(sk)      closesocket((sk))
#define LAST_ERROR()        WSAGetLastError()
typedef int socklen_t;
#endif//_WIN32

static int str2int(const char *str, unsigned int *pValue)
{
    unsigned int value;
    char *pEnd;

    value = strtoul(str, &pEnd, 10);
    if(NULL == pEnd || '\0' != *pEnd)
    {
        return EINVAL;
    }
    *pValue = value;
    return 0;
}

static int InitSocket(void)
{
#ifdef _WIN32
    WSADATA wd;

    return WSAStartup(MAKEWORD(2, 2), &wd);
#else
    return 0;
#endif//_WIN32
}

static void UnInitSocket(void)
{
#ifdef _WIN32
    WSACleanup();
#endif//_WIN32
}

static int ConnectSrv(const char *ip, unsigned short port, SOCKET &sock)
{
    int ret;
    SOCKET sktCli;
    
    sktCli = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(INVALID_SOCKET == sktCli)
    {
        ret = errno;
        printf("socket failed!ret=%d\n", ret);
        return ret;
    }

    struct sockaddr_in addrSer = { 0 };
    addrSer.sin_family = AF_INET;
    addrSer.sin_port = htons((unsigned short)port);
    addrSer.sin_addr.s_addr = inet_addr(ip);
    if(-1 == connect(sktCli, (sockaddr*)&addrSer, sizeof(addrSer)))
    {
        ret = errno;
        printf("connect failed!ret=%d\n", ret);
        CLOSE_SOCK(sktCli);
        return ret;
    }
    sock = sktCli;
    return 0;
}

int main(int argc, char* argv[])
{
    int ret;
    unsigned int port;
#ifndef _WIN32
    ssize_t len;
#else
    size_t len;
#endif//_WIN32
    SOCKET sktCli;
    char buf[1024] = {0};

    if (argc != 3)
    {
        fprintf(stderr, "usage: %s <ip> <port>\n", argv[0]);
        return EINVAL;
    }
    ret = str2int(argv[2], &port);
    if(0 != ret)
    {
        printf("Invalid port : %s", argv[2]);
        return ret;
    }
    else if (port == 0 || port > 65535)
    {
        printf("Invalid port : %s", argv[2]);
        return EINVAL;
    }
    ret = InitSocket();
    if(0 != ret)
    {
        printf("InitSocket failed!ret=%d\n", ret);
        return ret;
    }

    ret = ConnectSrv(argv[1], port, sktCli);
    if(0 != ret)
    {
        printf("ConnectSrv second failed!\n");
        UnInitSocket();
        return ret;
    }
    while (true)
    {
        printf(">>");
        buf[0] = '\0';
        if(NULL == fgets(buf, sizeof(buf), stdin) || '\0' == buf[0] || '\n' == buf[0] || '\r' == buf[0])
        {
            continue;
        }
        len = send(sktCli, buf, strlen(buf) + 1, 0);
        if (-1 == len)
        {
            ret = errno;
            printf("[-] send error!ret=%d\n", ret);
            break;
        }
        len = recv(sktCli, buf, sizeof(buf), 0);
        if (-1 == len)
        {
            ret = errno;
            printf("[-] recv error!ret=%d\n", ret);
            break;
        }
        else if(len > 0)
        {
            printf("[server] %s\n", buf);
        }
        else
        {
            ret = 0;
            printf("[-] server disconnect!\n");
            break;
        }
    }
    CLOSE_SOCK(sktCli);
    UnInitSocket();
    return ret;
}
